package com.chinafree.auth.service.impl;

import com.chinafree.auth.model.bo.LoginUserBo;
import com.chinafree.auth.model.bo.TokenMap;
import com.chinafree.auth.model.enumeration.VerficationEnum;
import com.chinafree.auth.model.po.SysLoginLog;
import com.chinafree.auth.model.result.LoginResult;
import com.chinafree.auth.service.LoginUserService;
import com.chinafree.auth.service.NormalLoginService;
import com.chinafree.auth.service.TokenService;
import com.chinafree.auth.service.VerificationCode;
import com.chinafree.common.model.enumeration.ResponseCodeEnum;
import com.chinafree.common.model.response.EntityResponse;
import com.chinafree.common.utils.MD5Utils;
import com.chinafree.common.utils.RegexUtils;
import com.chinafree.mapper.MaUserMapper;
import com.chinafree.mapper.SysLoginLogMapper;
import com.chinafree.model.po.MaUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
public class NormalLoginServiceImpl implements NormalLoginService {

    private static long PASSWORD_EFFECTIVE_TIME = 15 * 60;
    private static long TOKEN_EFFECTIVE_TIME = 100000000 * 60 * 60;
    public static String LOGIN_TIMES_PREFIX = "LOGIN_TIMES_";
    public static String TOKEN = "LG_";

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LoginUserService loginUserService;

    @Autowired
    private SysLoginLogMapper sysLoginLogMapper;
    @Autowired
    private VerificationCode verificationCode;
    @Autowired
    private MaUserMapper maUserMapper;

    @Override
    public EntityResponse<LoginResult> loginByUserNameAndPassword(String loginMail, String password, Integer roleId) {
        // 1. 从数据库获取loginUser
        LoginUserBo loginUserBo = queryLoginUser(loginMail);
        if (loginUserBo.getMsg() != null) {
            return new EntityResponse<>(ResponseCodeEnum.FORBIDDEN, loginUserBo.getMsg(), null);
        }
        // 2.判断密码是否正确,错误超多5次就冻结
        String msg = checkPassword(loginMail, password, loginUserBo);
        if (msg != null) {
            return new EntityResponse<>(ResponseCodeEnum.FORBIDDEN, msg, null);
        }
        // 3.构造loginResult
        EntityResponse<LoginResult> result = getLoginResult(loginUserBo, roleId);
        return result;
    }

    @Override
    public EntityResponse<LoginResult> getLoginByUserId(Long userId) {
        Optional<LoginUserBo> options = loginUserService.getUserId(userId);
        if (!options.isPresent()) {
            return new EntityResponse<>(ResponseCodeEnum.FORBIDDEN, "该手机号未注册", null);
        }

        return getLoginResult(options.get(), 2);
    }

    @Override
    public EntityResponse<LoginResult> loginByUserNameAndVerfication(String phone, String verfication, Integer roleId) {
        String msg = verificationCode.checkVerificationCode(VerficationEnum.LOGIN.getName(), phone, verfication);
        if (msg != null) {
            return new EntityResponse<>(ResponseCodeEnum.FORBIDDEN, msg, null);
        }
        Optional<LoginUserBo> loginUserByLoginMobile1 = loginUserService.getLoginUserByLoginMobile(phone);
        if (!loginUserByLoginMobile1.isPresent()) {
            return new EntityResponse<>(ResponseCodeEnum.FORBIDDEN, "该手机号未注册", null);
        }

        return getLoginResult(loginUserByLoginMobile1.get(), roleId);
    }

    @Autowired
    private TokenService tokenService;

    public EntityResponse<LoginResult> getLoginResult(LoginUserBo loginUserBo, Integer roleId) {
        LoginResult result = new LoginResult();
        // Integer roleIds = loginUserService.getRoleIds(roleId, loginUserBo.getId());
        result.setUserId(loginUserBo.getId());
        result.setUserName(loginUserBo.getLoginName());
        result.setRoleId(roleId);

        // 将loginId和userId存入redis中
        // 4.构造登录日志
        SysLoginLog build = SysLoginLog.builder()
                .loginName(result.getUserId().toString())
                .build();
        sysLoginLogMapper.insert(build);

        MaUser build1 = MaUser.builder().lastLoginTime(LocalDateTime.now()).build();
        build1.setId(loginUserBo.getId());
        maUserMapper.updateById(build1);

        TokenMap tokenMap = TokenMap.builder().roleId(roleId.toString()).userId(loginUserBo.getId().toString()).build();

        // 如果roleId = 2 则一定要有 companyId
        if (loginUserBo.getCompanyId() == null) {
            // 跳转到注册该身份的页面
            String token = tokenService.getToken(tokenMap);
            result.setToken(token);
            result.setIsCreatedRole(false);
            return new EntityResponse<>(ResponseCodeEnum.SUCCESS, "CompanyId不存在", result);
        } else {
            tokenMap.setCompanyId(loginUserBo.getCompanyId().toString());
        }
        ////////// 设置一个token
        String token = tokenService.getToken(tokenMap);
        result.setToken(token);

        result.setIsCreatedRole(true);
        return new EntityResponse<>(ResponseCodeEnum.SUCCESS, "登录成功", result);
    }

    /**
     * 判断密码是否正确,错误超多5次就冻结
     *
     * @param loginMail
     * @param password
     * @param loginUserBo
     */
    private String checkPassword(String loginMail, String password, LoginUserBo loginUserBo) {
        // 密码输入错误次数
        if (!redisTemplate.hasKey(LOGIN_TIMES_PREFIX + loginMail)) {
            if (StringUtils.isEmpty(loginUserBo.getPassword())) {
                return "您未设置密码!!";
            }
            // 错误密码记录不存在,验证用户密码是否正确
            if (!loginUserBo.getPassword().equals(MD5Utils.hash(password))) {
                // 密码错误,向redis插入错误密码的记录,提示密码错误
                redisTemplate.boundValueOps(LOGIN_TIMES_PREFIX + loginMail).set(0, 20L, TimeUnit.MINUTES);
                return "密码错误!";
            }
        } else {
            BoundValueOperations boundValueOperations = redisTemplate.boundValueOps(LOGIN_TIMES_PREFIX + loginMail);
            // 错误密码记录存在,就获取错误次数
            Integer cLoginTime = (int) boundValueOperations.get();
            if (cLoginTime < 5) {
                // 错误次数不到5次,可以继续验证用户密码是否正确
                if (!loginUserBo.getPassword().equals(MD5Utils.hash(password))) {
                    // 密码错误,错误次数+1并存入redis,提示密码错误
                    boundValueOperations.set(cLoginTime + 1, PASSWORD_EFFECTIVE_TIME);
                    boundValueOperations.expire(10L, TimeUnit.MINUTES);
                    return "密码错误!";
                }
            } else {
                // 错误次数达到5次,冻结用户,提示：输入密码错误超过5次请稍后重试
                return "输入密码错误超过5次，请稍后重试!";
            }
        }
        return null;
    }

    /**
     * 从数据库获取loginUser
     *
     * @param loginMail
     * @return
     */
    private LoginUserBo queryLoginUser(String loginMail) {
        LoginUserBo loginUserbo;
        // 判断loginMail是邮箱
        if (RegexUtils.checkMail(loginMail)) {
            // 根据邮箱获取用户
            Optional<LoginUserBo> loginUserByLoginMail = loginUserService.getLoginUserByLoginMail(loginMail);
            if (!loginUserByLoginMail.isPresent()) {
                return LoginUserBo.builder().msg("邮箱不存在").build();
            }
            loginUserbo = loginUserByLoginMail.get();
        } else if (RegexUtils.checkMobile(loginMail)) {
            // 根据手机号获取用户
            Optional<LoginUserBo> loginUserByLoginMobile = loginUserService.getLoginUserByLoginMobile(loginMail);
            if (!loginUserByLoginMobile.isPresent()) {
                return LoginUserBo.builder().msg("手机号不存在").build();
            }
            loginUserbo = loginUserByLoginMobile.get();
        } else {
            return LoginUserBo.builder().msg("邮箱或手机格式不正确").build();
        }
        if (loginUserbo == null) {
            // 用户不存在
            return LoginUserBo.builder().msg("用户不存在！").build();
        }
        return loginUserbo;

    }

}